// Copyright 2010 Alexandre Tristan St-Cyr <tristan.stcyr@gmail.com>

package com.codeplex.loadjava;

import java.util.HashSet;
import java.util.Set;

import com.codeplex.loadjava.model.ClassDefinition;
import com.codeplex.loadjava.model.Field;
import com.codeplex.loadjava.model.FieldDefinition;
import com.codeplex.loadjava.model.FieldReference;
import com.codeplex.loadjava.model.InterfaceImplementation;
import com.codeplex.loadjava.model.JavaClass;
import com.codeplex.loadjava.model.Method;
import com.codeplex.loadjava.model.MethodDefinition;
import com.codeplex.loadjava.model.MethodException;
import com.codeplex.loadjava.model.MethodInvocation;
import com.codeplex.loadjava.model.MethodParameter;
import com.codeplex.loadjava.model.TypeReference;


/**
 * Delegates to another visitor when Type, Classes, Methods or Fields entities
 * only when they haven't been visited.
 */
class BufferedJavaEntityAdapter implements IJavaModelVisitor {

	private Set<TypeReference> types = new HashSet<TypeReference>();
	
	private Set<JavaClass> classes = new HashSet<JavaClass>();
	
	private Set<Method> methods = new HashSet<Method>();
	
	private Set<Field> fields = new HashSet<Field>();
	
	private IJavaModelVisitor delegate;
	
	public BufferedJavaEntityAdapter(IJavaModelVisitor visitor) {
		this.delegate = visitor;
	}

	@Override
	public void visitField(Field field) {
		if (!this.fields.contains(field)) {
			this.fields.add(field);
			this.delegate.visitField(field);
		}
	}

	@Override
	public void visitMethod(Method method) {
		if (!this.methods.contains(method)) {
			this.methods.add(method);
			this.delegate.visitMethod(method);
		}
	}

	@Override
	public void visitClass(JavaClass javaClass) {
		if (!this.classes.contains(javaClass)) {
			this.classes.add(javaClass);
			this.delegate.visitClass(javaClass);
		}
	}

	@Override
	public void visitType(TypeReference typeReference) {
		if (!this.types.contains(typeReference)) {
			this.types.add(typeReference);
			this.delegate.visitType(typeReference);
		}
	}

	@Override
	public void visitFieldDefinition(FieldDefinition fieldDefinition) {
		this.delegate.visitFieldDefinition(fieldDefinition);
	}

	@Override
	public void visitMethodDefinition(MethodDefinition methodDefinition) {
		this.delegate.visitMethodDefinition(methodDefinition);
	}

	@Override
	public void visitMethodException(MethodException methodException) {
		this.delegate.visitMethodException(methodException);
	}

	@Override
	public void visitClassDefinition(ClassDefinition classDefinition) {
		this.delegate.visitClassDefinition(classDefinition);
	}

	@Override
	public void visitFieldReference(FieldReference fieldReference) {
		this.delegate.visitFieldReference(fieldReference);
	}

	@Override
	public void visitMethodInvocation(MethodInvocation methodInvocation) {
		this.delegate.visitMethodInvocation(methodInvocation);
	}

	@Override
	public void visitInterfaceImplementations(InterfaceImplementation interfaceImplementation) {
		this.delegate.visitInterfaceImplementations(interfaceImplementation);
	}

	@Override
	public void visitMethodParameter(MethodParameter parameter) {
		this.delegate.visitMethodParameter(parameter);
	}

	@Override
	public void visitClassFile(String relativePath) {
		this.delegate.visitClassFile(relativePath);
	}

	@Override
	public void endVisitClassFile(String relativePath) {
		this.delegate.endVisitClassFile(relativePath);
	}
}
